package security.lab1.main;

import java.io.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Arrays;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class SecurityLab1 {

	private byte[] encKey1;
	private byte[] encIV;
	private byte[] encKey2;
	private byte[] data;
	private byte[] plaintext;
	private Key privateKey;

	public void run() {
		try {
			getPrivateKey();
			readBytes();
			decryptKeys();
			decryptData();
			calculateMAC();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void calculateMAC() throws NoSuchAlgorithmException,
			InvalidKeyException, IOException {
		System.out.println("Calculating mac");
		
		Mac mac = Mac.getInstance("HmacMD5");
		Key key2 = new SecretKeySpec(encKey2, "HmacMD5");
		mac.init(key2);
		mac.update(plaintext);
		byte[] macbyte = mac.doFinal();
		File outputFile = new File(
				"/Applications/Android development/workspace/Security Lab 1/resources/mac.txt");
		FileOutputStream fos = new FileOutputStream(outputFile);
		fos.write(macbyte);
		fos.flush();
		fos.close();
	}

	private void decryptData() throws NoSuchAlgorithmException,
			NoSuchPaddingException, InvalidKeyException,
			InvalidAlgorithmParameterException, IllegalBlockSizeException,
			BadPaddingException, FileNotFoundException, IOException {
		System.out.println("Decrypting data");
		Key key1 = new SecretKeySpec(encKey1, "AES");
		IvParameterSpec params = new IvParameterSpec(encIV);
		Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
		aes.init(Cipher.DECRYPT_MODE, key1, params);

		byte[] dataDec = aes.doFinal(data);
		File outputFile = new File(
				"/Applications/Android development/workspace/Security Lab 1/resources/output.txt");
		FileOutputStream fos = new FileOutputStream(outputFile);
		fos.write(dataDec);
		fos.flush();
		fos.close();
	}

	private void decryptKeys() throws NoSuchAlgorithmException,
			NoSuchPaddingException, InvalidKeyException,
			IllegalBlockSizeException, BadPaddingException {
		System.out.println("Decrypting keys");

		Cipher rsa = Cipher.getInstance("RSA");
		rsa.init(Cipher.DECRYPT_MODE, privateKey);

		encKey1 = rsa.doFinal(encKey1);
		encIV = rsa.doFinal(encIV);
		encKey2 = rsa.doFinal(encKey2);
	}

	private void readBytes() throws FileNotFoundException, IOException {
		System.out.println("Reading bytes");
		File cipher = new File("resources/ciphertext.enc");
		FileInputStream fis = new FileInputStream(cipher);

		plaintext = new byte[fis.available()];
		fis.read(plaintext);
		fis.close();

		encKey1 = Arrays.copyOfRange(plaintext, 0, 128);

		encIV = Arrays.copyOfRange(plaintext, 128, 256);

		encKey2 = Arrays.copyOfRange(plaintext, 256, 384);

		data = Arrays.copyOfRange(plaintext, 384, plaintext.length);

	}

	private void getPrivateKey() throws FileNotFoundException,
			KeyStoreException, IOException, NoSuchAlgorithmException,
			CertificateException, UnrecoverableKeyException {
		System.out.println("Getting private key");
		String storePwd = "lab1StorePass";

		File storeFile = new File(
				"/Applications/Android development/workspace/Security Lab 1/resources/lab1Store");
		FileInputStream fis = new FileInputStream(storeFile);

		KeyStore keyStore = KeyStore.getInstance("JCEKS");
		keyStore.load(fis, storePwd.toCharArray());

		String keyPass = "lab1KeyPass";
		privateKey = keyStore.getKey("lab1EncKeys", keyPass.toCharArray());

		fis.close();
	}

}